// 性能优化工具集合

// 图片懒加载类
export class LazyImageLoader {
  private observer: IntersectionObserver | null = null
  private images: Map<Element, { src: string; placeholder?: string }> =
    new Map()

  constructor(options?: IntersectionObserverInit) {
    this.init(options)
  }

  private init(options?: IntersectionObserverInit): void {
    // #ifdef H5
    if (typeof window !== 'undefined' && 'IntersectionObserver' in window) {
      this.observer = new IntersectionObserver(
        this.handleIntersection.bind(this),
        {
          rootMargin: '50px',
          threshold: 0.1,
          ...options,
        }
      )
    }
    // #endif
  }

  private handleIntersection(entries: IntersectionObserverEntry[]): void {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        const img = entry.target as HTMLImageElement
        const imageData = this.images.get(img)

        if (imageData) {
          this.loadImage(img, imageData)
          this.observer?.unobserve(img)
          this.images.delete(img)
        }
      }
    })
  }

  private loadImage(
    img: HTMLImageElement,
    imageData: { src: string; placeholder?: string }
  ): void {
    const { src, placeholder } = imageData

    // 显示占位图
    if (placeholder) {
      img.src = placeholder
    }

    // 加载真实图片
    const realImg = new Image()
    realImg.onload = () => {
      img.src = src
      img.classList.add('loaded')
    }
    realImg.onerror = () => {
      img.classList.add('error')
    }
    realImg.src = src
  }

  // 添加图片到懒加载队列
  observe(img: HTMLImageElement, src: string, placeholder?: string): void {
    this.images.set(img, { src, placeholder })
    this.observer?.observe(img)
  }

  // 停止观察图片
  unobserve(img: HTMLImageElement): void {
    this.observer?.unobserve(img)
    this.images.delete(img)
  }

  // 销毁观察器
  destroy(): void {
    this.observer?.disconnect()
    this.images.clear()
  }
}

// 虚拟列表类
export class VirtualList<T> {
  private container: HTMLElement
  private itemHeight: number
  private visibleCount: number
  private buffer: number
  private items: T[]
  private startIndex: number = 0
  private endIndex: number = 0
  private scrollTop: number = 0
  private renderItem: (item: T, index: number) => HTMLElement

  constructor(
    container: HTMLElement,
    options: {
      itemHeight: number
      items: T[]
      renderItem: (item: T, index: number) => HTMLElement
      buffer?: number
    }
  ) {
    this.container = container
    this.itemHeight = options.itemHeight
    this.items = options.items
    this.renderItem = options.renderItem
    this.buffer = options.buffer || 5
    this.visibleCount =
      Math.ceil(container.clientHeight / this.itemHeight) + this.buffer * 2

    this.init()
  }

  private init(): void {
    this.container.style.overflow = 'auto'
    this.container.style.position = 'relative'

    // 设置总高度
    this.updateContainerHeight()

    // 监听滚动事件
    this.container.addEventListener('scroll', this.handleScroll.bind(this))

    // 初始渲染
    this.render()
  }

  private handleScroll(): void {
    this.scrollTop = this.container.scrollTop
    this.updateVisibleRange()
    this.render()
  }

  private updateVisibleRange(): void {
    const start = Math.floor(this.scrollTop / this.itemHeight)
    const end = Math.min(start + this.visibleCount, this.items.length)

    this.startIndex = Math.max(0, start - this.buffer)
    this.endIndex = Math.min(this.items.length, end + this.buffer)
  }

  private updateContainerHeight(): void {
    this.container.style.height = `${this.items.length * this.itemHeight}px`
  }

  private render(): void {
    // 清空容器
    this.container.innerHTML = ''

    // 创建可见项目
    for (let i = this.startIndex; i < this.endIndex; i++) {
      const item = this.items[i]
      const element = this.renderItem(item, i)

      element.style.position = 'absolute'
      element.style.top = `${i * this.itemHeight}px`
      element.style.height = `${this.itemHeight}px`
      element.style.width = '100%'

      this.container.appendChild(element)
    }
  }

  // 更新数据
  updateItems(items: T[]): void {
    this.items = items
    this.updateContainerHeight()
    this.updateVisibleRange()
    this.render()
  }

  // 滚动到指定项
  scrollToItem(index: number): void {
    const scrollTop = index * this.itemHeight
    this.container.scrollTop = scrollTop
  }

  // 销毁
  destroy(): void {
    this.container.removeEventListener('scroll', this.handleScroll.bind(this))
    this.container.innerHTML = ''
  }
}

// 防抖和节流装饰器
export function debounceMethod(delay: number) {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    const originalMethod = descriptor.value
    let timeoutId: number | null = null

    descriptor.value = function (...args: any[]) {
      if (timeoutId) {
        clearTimeout(timeoutId)
      }

      timeoutId = setTimeout(() => {
        originalMethod.apply(this, args)
      }, delay)
    }

    return descriptor
  }
}

export function throttleMethod(delay: number) {
  return function (
    target: any,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ) {
    const originalMethod = descriptor.value
    let lastCall = 0

    descriptor.value = function (...args: any[]) {
      const now = Date.now()

      if (now - lastCall >= delay) {
        lastCall = now
        originalMethod.apply(this, args)
      }
    }

    return descriptor
  }
}

// 内存管理工具
export class MemoryManager {
  private static cache = new Map<string, any>()
  private static maxSize = 50 // 最大缓存数量

  // 设置缓存
  static set(key: string, value: any, ttl?: number): void {
    // 如果缓存已满，删除最旧的项
    if (this.cache.size >= this.maxSize) {
      const firstKey = this.cache.keys().next().value
      this.cache.delete(firstKey)
    }

    const item = {
      value,
      timestamp: Date.now(),
      ttl: ttl || 0,
    }

    this.cache.set(key, item)
  }

  // 获取缓存
  static get(key: string): any {
    const item = this.cache.get(key)

    if (!item) return null

    // 检查是否过期
    if (item.ttl > 0 && Date.now() - item.timestamp > item.ttl) {
      this.cache.delete(key)
      return null
    }

    return item.value
  }

  // 删除缓存
  static delete(key: string): boolean {
    return this.cache.delete(key)
  }

  // 清空缓存
  static clear(): void {
    this.cache.clear()
  }

  // 获取缓存统计
  static getStats(): { size: number; maxSize: number; hitRate: number } {
    return {
      size: this.cache.size,
      maxSize: this.maxSize,
      hitRate: 0, // 需要实现命中率统计
    }
  }
}

// 性能监控工具
export class PerformanceMonitor {
  private static marks = new Map<string, number>()
  private static measures = new Map<string, number>()

  // 开始计时
  static start(name: string): void {
    this.marks.set(name, performance.now())
  }

  // 结束计时
  static end(name: string): number {
    const startTime = this.marks.get(name)
    if (!startTime) {
      console.warn(`Performance mark "${name}" not found`)
      return 0
    }

    const duration = performance.now() - startTime
    this.measures.set(name, duration)
    this.marks.delete(name)

    return duration
  }

  // 测量函数执行时间
  static measure<T>(name: string, fn: () => T): T {
    this.start(name)
    const result = fn()
    this.end(name)
    return result
  }

  // 异步测量函数执行时间
  static async measureAsync<T>(name: string, fn: () => Promise<T>): Promise<T> {
    this.start(name)
    const result = await fn()
    this.end(name)
    return result
  }

  // 获取性能报告
  static getReport(): Record<string, number> {
    return Object.fromEntries(this.measures)
  }

  // 清空记录
  static clear(): void {
    this.marks.clear()
    this.measures.clear()
  }
}

// 图片压缩工具
export class ImageCompressor {
  // 压缩图片
  static async compress(
    file: File,
    options: {
      maxWidth?: number
      maxHeight?: number
      quality?: number
      format?: string
    } = {}
  ): Promise<Blob> {
    const {
      maxWidth = 1920,
      maxHeight = 1080,
      quality = 0.8,
      format = 'image/jpeg',
    } = options

    return new Promise((resolve, reject) => {
      const canvas = document.createElement('canvas')
      const ctx = canvas.getContext('2d')
      const img = new Image()

      img.onload = () => {
        // 计算新尺寸
        let { width, height } = img

        if (width > maxWidth || height > maxHeight) {
          const ratio = Math.min(maxWidth / width, maxHeight / height)
          width *= ratio
          height *= ratio
        }

        // 设置画布尺寸
        canvas.width = width
        canvas.height = height

        // 绘制图片
        ctx?.drawImage(img, 0, 0, width, height)

        // 转换为Blob
        canvas.toBlob(
          (blob) => {
            if (blob) {
              resolve(blob)
            } else {
              reject(new Error('Failed to compress image'))
            }
          },
          format,
          quality
        )
      }

      img.onerror = () => reject(new Error('Failed to load image'))
      img.src = URL.createObjectURL(file)
    })
  }

  // 获取图片信息
  static getImageInfo(file: File): Promise<{
    width: number
    height: number
    size: number
    type: string
  }> {
    return new Promise((resolve, reject) => {
      const img = new Image()

      img.onload = () => {
        resolve({
          width: img.naturalWidth,
          height: img.naturalHeight,
          size: file.size,
          type: file.type,
        })
      }

      img.onerror = () => reject(new Error('Failed to load image'))
      img.src = URL.createObjectURL(file)
    })
  }
}

// 批量处理工具
export class BatchProcessor<T> {
  private batchSize: number
  private delay: number
  private processor: (items: T[]) => Promise<void>
  private queue: T[] = []
  private timeoutId: number | null = null

  constructor(
    processor: (items: T[]) => Promise<void>,
    options: { batchSize?: number; delay?: number } = {}
  ) {
    this.processor = processor
    this.batchSize = options.batchSize || 10
    this.delay = options.delay || 100
  }

  // 添加项目到批处理队列
  add(item: T): void {
    this.queue.push(item)

    if (this.queue.length >= this.batchSize) {
      this.process()
    } else if (!this.timeoutId) {
      this.timeoutId = setTimeout(() => {
        this.process()
      }, this.delay)
    }
  }

  // 处理队列
  private async process(): Promise<void> {
    if (this.queue.length === 0) return

    const items = this.queue.splice(0, this.batchSize)

    if (this.timeoutId) {
      clearTimeout(this.timeoutId)
      this.timeoutId = null
    }

    try {
      await this.processor(items)
    } catch (error) {
      console.error('Batch processing error:', error)
    }

    // 如果还有待处理的项，继续处理
    if (this.queue.length > 0) {
      this.timeoutId = setTimeout(() => {
        this.process()
      }, this.delay)
    }
  }

  // 强制处理所有剩余项
  async flush(): Promise<void> {
    if (this.timeoutId) {
      clearTimeout(this.timeoutId)
      this.timeoutId = null
    }

    while (this.queue.length > 0) {
      await this.process()
    }
  }
}

// 创建懒加载图片实例
export const lazyImageLoader = new LazyImageLoader()

// 导出工具函数
export const debounce = (fn: Function, delay: number) => {
  let timeoutId: number | null = null
  return (...args: any[]) => {
    if (timeoutId) clearTimeout(timeoutId)
    timeoutId = setTimeout(() => fn(...args), delay)
  }
}

export const throttle = (fn: Function, delay: number) => {
  let lastCall = 0
  return (...args: any[]) => {
    const now = Date.now()
    if (now - lastCall >= delay) {
      lastCall = now
      fn(...args)
    }
  }
}

export default {
  LazyImageLoader,
  VirtualList,
  MemoryManager,
  PerformanceMonitor,
  ImageCompressor,
  BatchProcessor,
  lazyImageLoader,
  debounce,
  throttle,
}
